package controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;

import model.BusinessCase;
import model.Case;
import model.ComponentWithBC;
import model.Criterion;
import model.Method;
import model.MethodApplication;
import model.GsonMapping.ComponentWithValue;
import model.GsonMapping.ReuseResultData;
import model.GsonMapping.ReuseSearchData;
import DAO.DAOFactory;
import DAO.SessionDAO;

import common.Enums.ComponentType;
import common.Enums.DAOType;
import common.Enums.DateRange;
import common.Exceptions.DAOException;
import common.Utils.CommonUtils;
import common.Utils.LinkedSet;

/**
 * Servlet implementation class ReuseServlet
 */
public class ReuseServlet extends BaseServlet 
{
	private static final long serialVersionUID = 1L;
	
	protected void loadSearchData(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		Gson gson = CommonUtils.createGsonInstance(response);
		
		try
		{
			ReuseSearchData searchData = new ReuseSearchData(100);
			response.getWriter().write(gson.toJson(searchData));
		}
		catch(Exception e)
		{
			StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
			String location = "Class: " + ste.getClassName() + ", method: " + ste.getMethodName();
			SessionDAO.getInstance().showError(location, e.getMessage(), e);
			
			response.getWriter().write(gson.toJson("ERROR"));
		}
	}
	
	private BusinessCase getRelatedBc(ComponentType cmpType, UUID cmpID) throws DAOException
	{
		BusinessCase retVal = null;
		
		MethodApplication metApp =  DAOFactory.getDAOFactory(DAOType.MYSQL).getMetAppDAO().getOriginMetApp(cmpType, cmpID);
		if(metApp != null)
			retVal = metApp.getBc();
		
		return retVal;
	}
	
	protected void loadComponentData(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		Gson gson = CommonUtils.createGsonInstance(response);
		
		try
		{
			
		}
		catch(Exception e)
		{
			StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
			String location = "Class: " + ste.getClassName() + ", method: " + ste.getMethodName();
			SessionDAO.getInstance().showError(location, e.getMessage(), e);
			
			response.getWriter().write(gson.toJson("ERROR"));
		}
	}
	
	protected void loadResultData(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		Gson gson = CommonUtils.createGsonInstance(response);
		
		try
		{
			DateRange dateRange = (request.getParameter("dateRange") != null) ? DateRange.valueOf(request.getParameter("dateRange")) : null;
			ComponentType cmpType = ComponentType.valueOf(request.getParameter("component"));
			String search = request.getParameter("search");
			UUID bcId = gson.fromJson(request.getParameter("bcID"), UUID.class);
			UUID parentMetID = gson.fromJson(request.getParameter("parentMetID"), UUID.class);
			LinkedSet<ReuseResultData<?>> resultData = new LinkedSet<ReuseResultData<?>>();
			String returnJsonData = "";
			
			switch(cmpType)
			{
				case CASE:
					
					List<ComponentWithBC<Case>> components = DAOFactory.getDAOFactory(DAOType.MYSQL).getMetAppDAO().getCaseByFilters(bcId, SessionDAO.getInstance().getCachedBC().getID(), dateRange, search);
					for(ComponentWithBC<Case> cmp : components)
					{
						ReuseResultData<Case> rrd = new ReuseResultData<Case>(cmp.getBc(), cmp.getComponent());
						resultData.add(rrd);
					}
					
					returnJsonData = gson.toJson(resultData);
					break;
					
				case CRITERION:

					List<ComponentWithBC<Criterion>> criteria = DAOFactory.getDAOFactory(DAOType.MYSQL).getMetAppDAO().getCriterionByFilters(bcId, parentMetID, dateRange, search);
					for(ComponentWithBC<Criterion> cmp : criteria)
					{
						ReuseResultData<Criterion> rrd = new ReuseResultData<Criterion>(cmp.getBc(), cmp.getComponent());
						resultData.add(rrd);
					}
					
					returnJsonData = gson.toJson(resultData);
					break;
					
				case METHOD:
					if(bcId != null)
					{
						List<ComponentWithBC<Method>> methods = DAOFactory.getDAOFactory(DAOType.MYSQL).getMetAppDAO().getMethodByFilters(bcId, dateRange, search);
						for(ComponentWithBC<Method> cmp : methods)
						{
							ReuseResultData<Method> rrd = new ReuseResultData<Method>(cmp.getBc(), cmp.getComponent());
							resultData.add(rrd);
						}
					} 
					else
					{
						List<Method> methods = DAOFactory.getDAOFactory(DAOType.MYSQL).getMethodDAO().getMethodsByFilters(search, dateRange); 
						for(Method met : methods)
						{
							BusinessCase bc = getRelatedBc(cmpType, met.getID());
							ReuseResultData<Method> rrd = new ReuseResultData<Method>(bc, met);
							resultData.add(rrd);
						}
					}
					returnJsonData = gson.toJson(resultData);
					break;
					
				case VALUE:
					List<MethodApplication> metApps = DAOFactory.getDAOFactory(DAOType.MYSQL).getMetAppDAO().getValuesByFilters(bcId, dateRange, search);
					returnJsonData = gson.toJson(metApps);
					break;
			}
			
			response.getWriter().write(returnJsonData);
		}
		catch(Exception e)
		{
			StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
			String location = "Class: " + ste.getClassName() + ", method: " + ste.getMethodName();
			SessionDAO.getInstance().showError(location, e.getMessage(), e);
			
			response.getWriter().write(gson.toJson("ERROR"));
		}
	}
	
	protected void loadCriterionValues(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		Gson gson = CommonUtils.createGsonInstance(response);
		
		try
		{
			UUID crtID = gson.fromJson(request.getParameter("param"), UUID.class);
			//UUID parentMetID = gson.fromJson(request.getParameter("parentMetID"), UUID.class);
			//TODO: Filter by the cases that are present in the CURRENT top level method (parentMetID), currently it shows all mapped including for different cases...
			
			HashMap<UUID, ComponentWithValue> criterionValues = new HashMap<UUID, ComponentWithValue>();
			for(MethodApplication metApp : DAOFactory.getDAOFactory(DAOType.MYSQL).getMetAppDAO().getAllByCriterionID(crtID))
				if(metApp.getCriterion() != null && metApp.getCriterion().getID().equals(crtID))
				{
					ComponentWithValue crtValue = new ComponentWithValue(metApp.getValue(), metApp.getMethod().getID(), metApp.getID(), metApp.getCaso());
					criterionValues.put(metApp.getCaso().getID(), crtValue);
				}
		
			if(criterionValues.size() == 0)
				criterionValues = null;
			
			response.getWriter().write(gson.toJson(criterionValues));
		}
		catch (Exception e) 
		{
			StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
			String location = "Class: " + ste.getClassName() + ", method: " + ste.getMethodName();
			SessionDAO.getInstance().showError(location, e.getMessage(), e);
			
			response.getWriter().write(gson.toJson("ERROR"));
		}
	}
	
	protected void loadCaseValues(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		Gson gson = CommonUtils.createGsonInstance(response);
		
		try
		{
			UUID casID = gson.fromJson(request.getParameter("param"), UUID.class);
			UUID parentMetID = gson.fromJson(request.getParameter("parentMetID"), UUID.class);
			
			HashMap<UUID, ComponentWithValue> caseValues = new HashMap<UUID, ComponentWithValue>();
			for(MethodApplication metApp : SessionDAO.getInstance().getMethodsApplication())
				if(metApp.getParentMetID() != null && metApp.getParentMetID().equals(parentMetID))
					if(metApp.getCaso() != null && metApp.getCaso().getID().equals(casID) && metApp.getCriterion() != null)
					{
						//TODO: Not insert derived measure results and final method result...
						ComponentWithValue casValue = new ComponentWithValue(metApp.getValue(), metApp.getMethod().getID(), metApp.getID(), metApp.getCriterion());
						caseValues.put(metApp.getCriterion().getID(), casValue);
					}
		
			response.getWriter().write(gson.toJson(caseValues));
		}
		catch (Exception e) 
		{
			StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
			String location = "Class: " + ste.getClassName() + ", method: " + ste.getMethodName();
			SessionDAO.getInstance().showError(location, e.getMessage(), e);
			
			response.getWriter().write(gson.toJson("ERROR"));
		}
	}
}
